Skip to main content
Version: DeepHub 2022 R2 - 2.2.3

Security & Authorization

DeepHub® uses the OpenID standard to secure access to the API. This document describes how to apply permission settings to individual API endpoints and OpenID users, and provides an example OpenID setup using Keycloak as OpenID server. Though any standard OpenID server can be used. Also refer to the Server Configuration readme for OpenID configuration options.

Enable Authorization

In order to enable authorization features permissions, OpenID and server configurations need to be configured accordingly. The following gives a quick overview about files and configuration options which need to be configured to enable authorization and security features:

In hub_config.yaml

  • require_authorization must be set to true
  • openid_client_name must be set to verify audiences. This is mandatory by OpenID, see also the audience claim setup example below.
  • verify_authserver set to true when running the server in production mode (requires authserver_public_key_path).
  • authserver_public_key_path should point to the public key of the OpenID server when running in production mode
  • force_https should be set to true in production mode to disable any insecure plain http or websocket communication
  • openid_config_url must be set to the standard OpenID configuration endpoint, e.g.
openid_config_url: http://127.0.0.1:8080/auth/realms/omlox/.well-known/openid-configuration

In permissions.yaml

Authorization to the API is controlled in this file (more Details in the next section).

Server certificates

When running the server in production mode, appropriate settings such as server certificates, public_key_path, private_key_path and dh_params_path must be set. Please refer to the Server Configuration.

Authorization Flow Type

DeepHub uses Bearer Authorization for the REST API. Clients connecting to the hub will never send passwords directly to the hub. Instead clients login to the OpenID server and provide the bearer token with each request header to the Hub. The hub is able to securely verify the token is valid and was issued by the configured OpenID server.

For service-to-service and client-to-service communication we advise to use bearer authorization. For web clients we advise to use Authorization Code Flow for secure login. An Angular web client example is located in the examples/angular-oidc-sample-code-flow folder.

Applying individual REST API Permissions

DeepHub server uses an RBAC (Role Based Access Control) model to assign permissions to OpenID roles. The permissions are stored in a YAML based file in the data directory of the Docker container. The permissions are loaded once at startup.

General structure of the permissions file:

role-name:
description: Some role description
'/api/path':
- PERMISSION1
- PERMISSION2
'/api/path_2/*':
- PERMISSION1
'/api/path_3/:resource_id':
- PERMISSION1
...

Description of the core elements:

  • role-name must match an actual OpenID role name provided as part of the JWT Access Token.

  • /api/path must match an actual DeepHub API endpoint (refer to the OpenAPI file for a list of available endpoints).

  • The * symbol is a wildcard, allowing to give permissions to all subpaths of an API, e.g. /api/path_2/* will match all subpaths like /api/path_2/a, /api/path_2/b etc.

  • A path for a given role should only be specified once. Duplicates will produce an error.

  • Permission can be any of the following (multiple entries possible): CREATE_ANY, READ_ANY. UPDATE_ANY, DELETE_ANY, CREATE_OWN, READ_OWN, UPDATE_OWN, DELETE_OWN. Note that the respective ANY and OWN permissions are mutually exclusive, i.e., for a given path a role can have either READ_ANY or READ_OWN, but not both. Refer to the description below to choose the right permission.

  • :resource_id is a placeholder variable, matching identifiers given as part of a request. For example, the permission URL /v1/providers/:provider_id/location will match the HTTP GET request to /v1/providers/provider123/location, and map the placeholder variable provider_id to the value "provider123". When the permission for the URL is one of CREATE_OWN, READ_OWN, UPDATE_OWN, DELETE_OWN then the client is required to provide ownership proof with his access token. The structure of the required access token is described below.
    Important: The placeholder variables must match the names defined in the OpenAPI specification, e.g. it's required to use :provider_id for the route /v1/providers/:provider_id. The placeholder variable's name is used to match named resource identifiers provided with the access token, thus a mismatch will result in failed authorization.

Permission types

CREATE_ANY
The role is allowed to create (e.g. via POST request) a resource at the given API path.

READ_ANY
The role is allowed to read all resource objects at a given API path.

UPDATE_ANY
The role is allowed to update (e.g. via PUT request) resources at given API path.

DELETE_ANY
The role is allowed to delete all resources for a given API path.

CREATE_OWN, READ_OWN, UPDATE_OWN, DELETE_OWN
The role is only allowed to read or mutate it's own resources. Resource ownership is defined via JWT AccessToken. A particular user which owns a resource must have a matching resource UUID in the Access Token.

Permissions example

In the example below a role named omlox-api-role is provided full admin access to all API endpoints using a wildcard match:

omlox-api-role:
description: Super user with all permissions
'/v1/*':
- CREATE_ANY
- READ_ANY
- UPDATE_ANY
- DELETE_ANY

In this example a user is given access restricted to his own location data:

omlox-api-role:
description: A user with access to only his own location data
'/v1/providers/:provider_id/*':
- CREATE_OWN
- READ_OWN
- UPDATE_OWN
- DELETE_OWN

Applying Permissions to Websocket Topics

Permissions to websocket topics follow the same rules as the permissions for the REST API. The url paths use the following scheme: /v1/ws/socket/topic/:resource_id

In the scheme above, topic is a placeholder for the actual websocket topic name, e.g. "location_updates", and :resource_id is a placeholder for the identifier name which must match the data for this topic using the same rules and naming scheme as stated for the REST API.

For an example, a permission to access only own location data which matches a provider_id given as part of the access token looks as follows:

read-only-own-resources-role:
'/v1/ws/socket/location_updates/:provider_id':
- CREATE_OWN
- READ_OWN
- UPDATE_OWN
- DELETE_OWN

Wildcards can be applied in the same way as for the REST API, for example /v1/ws/socket/location_updates/* would match location updates for all location providers.

Access Token extension for ownership claims

In order to allow access to ownership restricted URLs the access token must contain an object member named https://deephub.io/owned_resources containing named lists to resource identifiers. The member names must adhere to the following scheme:

placeholder_variable + 's'

In other words, the name of the members is the plural of the placeholder variable name. As an example, the json content of an access token looks like this:

{
"https://deephub.io/owned_resources": {
"provider_ids": [
"provider123"
],
"trackable_ids": [
"trackable123"
],
"zone_ids": [
"zone123"
],
"fence_ids": [
"fence123"
]
},
...
}

Example OpenID setup with Keycloak

An OpenID server is required in order to enable authorization features in DeepHub. Below is an example using Keycloak, though the basic setup should work similar for other OpenID servers.

Prerequisites: A running Keycloak instance. You can start with a simple standalone instance for development and testing. See the Keycloak guide to get started.

At first we have to create an omlox™ realm:

  • Go to http://localhost:8080/auth/admin/ and log in to the Keycloak Admin Console using the account.
  • From the Master drop-down menu, click Add Realm.
  • Type omlox™ in the Name field and click Create.

Next we create the role omlox™-api-role for Hub API access. To do so:

  • From the menu, click Roles to open the roles list.
  • Click on Add Role on the right side of the list
  • Enter omlox™-api-role in the Role Name field. The role name must not be changed, because this role name is mapped to omlox™ permissions.

Next we create a user named omlox™-api-user. To create a new user in the omlox™ realm, complete the following steps:

  • Make sure the omlox™ Realm is the selected current Realm in the Master drop-down menu
  • From the menu, click Users to open the user list page.
  • On the right side of the user list, click Add User to open the add user page.
  • Enter the name omlox™-api-user in the Username field. Flip the Email Verified switch from Off to On and click Save to save the data and open the management page for the new user.
  • Click the Credentials tab and enter a password for the new user. Flip the Temporary switch to Off to make the new password permanent. Click Set Password to save the changes.
  • Click the Role Mappings tab. In the Realm Roles list, select omlox™-api-role and click the Add selected button.

Next we create a client named omlox™-api-client. To create a new user in the omlox™ realm, complete the following steps:

  • Make sure the omlox™ Realm is the selected current Realm in the Master drop-down menu
  • From the menu, click Clients to open the client list page.
  • On the right side of the client list, click Create to open the create client page.
  • Enter the name omlox™-api-client in the Client ID field. Select openid-connect in the Client Protocol dropdown.
  • Select Public as Access Type
  • Toggle Service Accounts Enabled. This enables Client Credentials Grant workflow for the Hub to fetch access tokens for token verification of client requests.
  • Click Save.

Next, create another client to be used by the hub service itself. Note: This client is mandatory even in case no other OpenID exists to communicate with the hub, and the client name must match with the openid_client_name in the hub config. All other OpenID clients which communicate with the hub have to include this client in the JWT as audience, so that the hub can verify audiences as mandated by OpenID.

  • Repeat the previous step to create a client.
  • Name deephub-service. Note: The name is case-sensitive and must match the one in the configuration file.
  • Set the Access Type to bearer-only.
  • Click Save.

For security reasons an OpenID enabled service has to verify audience claims in order to avoid token misuse. Follow these steps:

  • From the meu, click Client Scopes to open the client scopes list.
  • Click Create to create a new client scope.
  • Enter hub-service into the Name field.
  • Click the Save button to create the new client scope.
  • In the list of client scopes, select the newly created hub-service.
  • Select Mappers from the top menu.
  • Click the Create button on the right side.
  • Enter hub-service-audience into the Name field.
  • From the Mapper Type selection choose Audience.
  • In the Included Client Audience select deephub-service.
  • Click Save button to save the changes.
  • Now we create a mapping between the newly created scope and the client used for user logins. From the left menu panel, choose Clients and choose omlox™-api-client.
  • From either the Default Client Scopes or Optional Client Scopes list select hub-service and click on Add selected. You can only add it to either default or optional. The difference is that when you add it to the default list the token will always contain the audience hub-service. When you set it to optional the user client (e.g. web application) must explicitly set the scope to hub-service when requesting the token, the token will then contain the audience deephub-service. It’s advised to use the optional mapper and limit scopes appropriately on the user client side.

Optional steps It’s possible to define fine-grained ownership permissions by adding custom attributes to a user. This allows for assigning read_own permissions to API paths which are restricted to users that own a particular resource. Follow these steps:

  • From the left menu, click Clients.
  • From the clients list, select omlox-api-client. From the top menu select Mappers.
  • Click on the Create button to create a new mapper.
  • Set a name like Assigned Location Providers.
  • In the Mapper Type selection, select User Attribute.
  • In the User Attribute field, set https://deephub.io/owned_resources/provider_ids (Important: This field must match with the one we set in the User attributes for the particular user.
  • In the Token Claim Name field, set https://deephub\.io/owned_resources.provider_ids (without quotes). It’s important to use this exact name, as the DeepHub will check if a user has access to particular resources using this name. Also note the \ and . in this name. This will actually create a json member named https://deephub.io/owned_resources with an object named provider_ids.
  • From the Claim JSON Type selection, select String.
  • Enable Multivalued.
  • Click Save

Repeat the above steps to create respective mappers for fences, trackables and zones as well, using the following values.

For fence ownership mapping:

  • Set User Attribute to: https://deephub.io/owned_resources/fence_ids
  • Set Token Claim Name to: https://deephub\.io/owned_resources.fence_ids

For trackable ownership mapping:

  • Set User Attribute to: https://deephub.io/owned_resources/trackable_ids
  • Set Token Claim Name to: https://deephub\.io/owned_resources.trackable_ids

For zone ownership mapping:

  • Set User Attribute to: https://deephub.io/owned_resources/zone_ids
  • Set Token Claim Name to: https://deephub\.io/owned_resources.zone_ids

For source ownership mapping:

  • Set User Attribute to: https://deephub.io/owned_resources/source_ids
  • Set Token Claim Name to: https://deephub\.io/owned_resources.source_ids

Now we can create actual user attributes which will then be mapped at runtime. To assign a Location Provider to a user, follow these steps:

  • In the left menu bar, click Users
  • Choose a user from the list to whom you want to assign a trackable
  • Click Attributes.
  • In the attributes key / value list, set key to https://deephub.io/owned_resources/provider_ids and the value to the ID of the Location Provider you want to assign to the user (e.g. 5896823C-3B3F-48BB-B74B-E43041ABD59C).

Repeat the above steps for fences, trackables, zones, and sources using the respective keys below:

  • https://deephub.io/owned_resources/fence_ids
  • https://deephub.io/owned_resources/trackable_ids
  • https://deephub.io/owned_resources/zone_ids
  • https://deephub.io/owned_resources/source_ids

Note: You can set multiple entries in the value field using "##" as delimiter between entries. For example:

providerid1##providerid2

This will show as two items in the provider_ids array.

Further note: source_ids refer to the source given in a location update. This source can reference a zone, but doesn't have to. As such, source_ids should contain all zone ids in addition to other source ids. At this point some double book keeping is required.

[1] https://www.keycloak.org/docs/latest/server_installation/